#ifndef ESP32USBMSC_H
#define ESP32USBMSC_H

#include <USB.h>
#include <USBMSC.h>
#include <SD_MMC.h>

/**
 * @brief ESP32 USB Mass Storage Class (MSC) 类
 *
 * 这个类实现了将 ESP32 的 SD 卡作为 USB 大容量存储设备的功能。
 * 使用单例模式确保只有一个实例存在。
 *
 * 使用示例：
 * @code
 * #include "ESP32USBMSC.h"
 *
 * void setup() {
 *   // 初始化 SD_MMC
 *   SD_MMC.setPins(40, 39, 41, 42, 48, 38);
 *   if (!SD_MMC.begin("/sdcard", false)) {
 *     Serial.println("SD 卡初始化失败");
 *     return;
 *   }
 *
 *   // 设置 U 盘信息
 *   usbMsc.setVendorID("MyCompany");
 *   usbMsc.setProductID("MyUSBDrive");
 *   usbMsc.setProductRevision("1.0");
 *
 *   // 初始化 USB MSC
 *   if (!usbMsc.begin(&SD_MMC)) {
 *     Serial.println("USB MSC 初始化失败");
 *     return;
 *   }
 * }
 * @endcode
 */
class ESP32USBMSC
{
private:
    USBMSC msc;                   ///< USB MSC 对象
    static ESP32USBMSC *instance; ///< 单实例指针
    void *storage;                ///< 存储设备指针
    bool mscMounted = false;      ///< MSC 挂载状态
    static bool usbConnected;     ///< USB 连接状态

    // 定义USB事件回调函数类型
    typedef void (*UsbEventCallback)(int32_t event_id, void *event_data);
    static UsbEventCallback userUsbEventCallback; ///< 用户注册的回调函数指针

    // 定义挂载/卸载回调函数类型
    typedef void (*MountCallback)(bool mounted);
    static MountCallback userMountCallback; ///< 用户注册的挂载回调函数指针

    /**
     * @brief 静态读取回调函数
     * @param lba 逻辑块地址
     * @param offset 偏移量
     * @param buffer 数据缓冲区
     * @param bufsize 缓冲区大小
     * @return 实际读取的字节数
     */
    static int32_t staticOnRead(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize);

    /**
     * @brief 静态写入回调函数
     * @param lba 逻辑块地址
     * @param offset 偏移量
     * @param buffer 数据缓冲区
     * @param bufsize 缓冲区大小
     * @return 实际写入的字节数
     */
    static int32_t staticOnWrite(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize);

    /**
     * @brief 静态启动/停止回调函数
     * @param power_condition 电源条件
     * @param start 是否启动
     * @param load_eject 是否加载/弹出
     * @return 操作是否成功
     */
    static bool staticOnStartStop(uint8_t power_condition, bool start, bool load_eject);

    /**
     * @brief 静态 USB 事件回调函数
     * @param arg 参数
     * @param event_base 事件基
     * @param event_id 事件 ID
     * @param event_data 事件数据
     */
    static void staticUsbEventCallback(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);

    /**
     * @brief 读取回调函数
     * @param lba 逻辑块地址
     * @param offset 偏移量
     * @param buffer 数据缓冲区
     * @param bufsize 缓冲区大小
     * @return 实际读取的字节数
     */
    int32_t onRead(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize);

    /**
     * @brief 写入回调函数
     * @param lba 逻辑块地址
     * @param offset 偏移量
     * @param buffer 数据缓冲区
     * @param bufsize 缓冲区大小
     * @return 实际写入的字节数
     */
    int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize);

    /**
     * @brief 启动/停止回调函数
     * @param power_condition 电源条件
     * @param start 是否启动
     * @param load_eject 是否加载/弹出
     * @return 操作是否成功
     */
    bool onStartStop(uint8_t power_condition, bool start, bool load_eject);

    /**
     * @brief USB 事件回调函数
     * @param arg 参数
     * @param event_base 事件基
     * @param event_id 事件 ID
     * @param event_data 事件数据
     */
    void usbEventCallback(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);

    /**
     * @brief 私有构造函数，防止外部创建实例
     */
    ESP32USBMSC();

public:
    /**
     * @brief 注册USB事件回调函数
     * @param cb 回调函数指针
     */
    static void registerUsbEventCallback(UsbEventCallback cb);

    /**
     * @brief 注册挂载回调函数
     * @param cb 挂载回调函数指针
     */
    static void registerMountCallback(MountCallback cb);

    /**
     * @brief 删除拷贝构造函数
     */
    ESP32USBMSC(const ESP32USBMSC &) = delete;

    /**
     * @brief 删除赋值运算符
     */
    ESP32USBMSC &operator=(const ESP32USBMSC &) = delete;

    /**
     * @brief 获取单实例
     * @return ESP32USBMSC 实例的引用
     */
    static ESP32USBMSC &getInstance();

    /**
     * @brief 设置厂商ID
     * @param vendorID 厂商ID字符串
     */
    void setVendorID(const char *vendorID);

    /**
     * @brief 设置产品ID
     * @param productID 产品ID字符串
     */
    void setProductID(const char *productID);

    /**
     * @brief 设置产品版本号
     * @param revision 版本号字符串
     */
    void setProductRevision(const char *revision);

    /**
     * @brief 初始化USB MSC设备
     * @param storageDevice 存储设备指针
     * @return 初始化是否成功
     */
    bool begin(void *storageDevice);

    /**
     * @brief 手动挂载USB MSC设备
     *
     * 该函数会：
     * 1. 设置自动挂载标志为true
     * 2. 设置存储设备为就绪状态
     * 3. 初始化USB MSC设备
     * 4. 启动USB功能
     * 5. 注册USB事件回调
     * 6. 触发挂载回调函数
     *
     * 注意：如果设备已经挂载，重复调用此函数不会产生任何效果
     */
    void mountMSC();

    /**
     * @brief 手动卸载USB MSC设备
     *
     * 该函数会：
     * 1. 设置自动挂载标志为false
     * 2. 结束USB MSC设备
     * 3. 记录卸载时间戳（用于延时保护）
     * 4. 触发卸载回调函数
     *
     * 注意：
     * 1. 卸载后需要等待安全延时才能进行文件操作
     * 2. 如果设备已经卸载，重复调用此函数不会产生任何效果
     */
    void unmountMSC();

    /**
     * @brief 获取当前挂载状态
     * @return true: 设备已挂载
     *         false: 设备未挂载
     */
    bool isMounted() const { return mscMounted; }
};

// 声明全局单实例
extern ESP32USBMSC &usbMsc;

#endif // ESP32USBMSC_H